
#ifndef _PARSETREE_
#define _PARSETREE_

#include "RuleType.h"
#include "Visiter.h"
#include <TokenHierarchy.h>

/**
* ParseTree
*/
class Tree {
	
	Tree* left;
	Tree* right;
	Tree* parent;

	int type;
public:
	
	Tree(int ruleType) {
		this->type = ruleType;
		this->left=0;
		this->right=0;
 }

	Tree(){
	}
	
	~Tree() {
		if(left)
			delete left;
		if(right)
			delete right;
	}
	
	virtual void addNode(Tree* node) {
		
		node->setParent(this);

		
		if(!left){
			this->left = node;
		}else{
			this->right = node;
		}
		
	}
	
	virtual Value* accept(Evaluator* eval) {
		
		switch(this->type) {
			case RuleType::EXP:
				return eval->eval_Exp(this);
				break;
			case RuleType::STATEMENT_1:
				eval->eval_Statement_1(this);
				break;
			case RuleType::STATEMENT_2:
				eval->eval_Statement_2(this);
				break;
			case RuleType::STATEMENTLIST:
				eval->eval_StatementList(this);
				break;
			case RuleType::STATEMENTLIST2:
				eval->eval_StatementList2(this);
				break;
			case RuleType::OP_PLUS:
				return eval->eval_OP_Plus(this);
				break;
			case RuleType::OP_MULT:
				return eval->eval_OP_Mult(this);
				break;
			case RuleType::OP_MINUS:
				return eval->eval_OP_Minus(this);
				break;
			case RuleType::OP_EXP_2:
				return eval->eval_OP_Exp_2(this);
				break;
			case RuleType::OP_EXP_1:
				return eval->eval_OP_Exp_1(this);
				break;
			case RuleType::OP_DURCH:
				return eval->eval_OP_Durch(this);
				break;
			case RuleType::OP_DIV:
				return eval->eval_OP_Div(this);
				break;
			case RuleType::OP_MOD:
				return eval->eval_OP_Mod(this);
				break;
			case RuleType::EXPLIST2:
				return eval->eval_ExpList2(this);
				break;
			case RuleType::EXP3_2:
				return eval->eval_Exp3_2(this);
				break;
			case RuleType::EXPLIST:
				return eval->eval_ExpList(this);
				break;
			case RuleType::EXP3_1:
				return eval->eval_Exp3_1(this);
				break;
			case RuleType::EXP2_SUM:
				return eval->eval_Exp2_Sum(this);
				break;
			case RuleType::EXP2_REAL:
				return eval->eval_Exp2_Real(this);
				break;
			case RuleType::EXP2_PROD:
				return eval->eval_Exp2_Prod(this);
				break;
			case RuleType::EXP2_MINUS_EXP2:
				return eval->eval_Exp2_MinusExp2(this);
				break;
			case RuleType::EXP2_INT:
				return eval->eval_Exp2_Int(this);
				break;
			case RuleType::EXP2_EXP3:
				return eval->eval_Exp2_Exp3(this);
				break;
		}
	}
	
	void setParent(Tree* parent) {
		this->parent = parent; 
	}
	
	Tree* getParent() {
		return this->parent;
	}
	
	bool isRoot() {
		return !(bool)this->parent;
	}

	Tree* getLeft() const {
		return this->left;
	}

	Tree* getRight() const {
		return this->right;
	}

	int getType() const {
		return this->type;
	}
};

class Node : public Tree {
	int type;

public:
	//Allgemeiner Knoten
	Node(int ruleType) : Tree(ruleType) {
		this->type = ruleType;
	}

};

class Blatt : public Tree {
	Token* tok;
	int type;

public:

	//R�ckgabe Token
	Token* getToken() const {
		return this->tok;
	}

	Blatt(Token* tok){
		this->tok = tok;
	}

	//Allgemeiner Knoten
	Blatt(int ruleType) : Tree(ruleType) {
		this->type = ruleType;
	}

	void setToken(Token* tok) {
		this->tok = tok;
	}
};
#endif //_PARSETREE_